﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.WebUtilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using WebLog.Db.SqlLogHelpers;

namespace WebLog
{
    public static class UseWebLogExtend
    {
        public static IApplicationBuilder UseWebLog(this IApplicationBuilder app)
        {
            //接口映射
            BindWebLogService(app);
            //路径映射（需要把文件设置成始终输出）
            WebLogResourcesResponse(app);
            return app;
        }

        /// <summary>
        /// json序列化以小写开头
        /// </summary>
        private static JsonSerializerSettings CamelCase = new JsonSerializerSettings()
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver(),
            DateTimeZoneHandling = DateTimeZoneHandling.Local,
            DateFormatString = "yyyy-MM-dd HH:mm:ss",
        };
        static Guid GetAndSetWLogId(HttpContext httpC)
        {
            Guid result;
            if (httpC.Request.Cookies["wlogId"].IsNullEmpty() && !httpC.Request.Cookies["wlogId"].IsGuidByReg())
                httpC.Response.Cookies.Append("wlogId", (result = Guid.NewGuid()).ToString(), new CookieOptions
                {
                    Expires = DateTimeOffset.Now.AddDays(360)
                });
            else result = new Guid(httpC.Request.Cookies["wlogId"]);
            return result;
        }
        /// <summary>
        /// 创建自定义服务
        /// 并映射在路由上
        /// </summary>
        /// <param name="app"></param>
        private static void BindWebLogService(IApplicationBuilder app)
        {
            Dictionary<string, Func<HttpContext, object>> myService = new Dictionary<string, Func<HttpContext, object>> { };
            string px = "/WeblogApi/";
            #region config
            myService.Add(px + "GetConfig", (httpC) =>//这个接口暂时只支持 Query
            {
                return WebLogHelper.Config;
            });
            myService.Add(px + "SetConfig", (httpC) =>//这个接口暂时只支持 Query
            {
                var dto = new ConfigInputDto { };
                httpC.Request.GetDtoByRequest("Query", dto);
                return WebLogHelper.SetConfig(dto);
            });
            #endregion config
            myService.Add(px + "GetAllLog", (httpC) =>//这个接口暂时只支持 Query
            {
                try
                {
                    if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                    var dto = httpC.Request.GetDtoByRequest("Body", new SearchLogInputDto()) ?? httpC.Request.GetDtoByRequest("Form", new SearchLogInputDto());
                    dto.wlogid = GetAndSetWLogId(httpC);
                    return WebLogHelper.SearchLog(dto);
                }
                catch (Exception ex)
                {

                    throw;
                }
                
            });
            myService.Add(px + "GetSearchLogDtoHistorys", (httpC) =>//这个接口暂时只支持 Query
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                var wlogid = GetAndSetWLogId(httpC);
                return Extends.SearchExtend.GetSearchLogDtoHistorys(wlogid);
            });
            myService.Add(px + "SqlLog/GetAll", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                var dto = httpC.Request.GetDtoByRequest("Query", new SearchLogInputDto());
                if (!dto.ID.HasValue || dto.ID < 1) return new { msg = "传递参数有误！" };
                return WebLogHelper.SearchSqlLog(dto.ID.Value);
            });
            #region SqlLogPath 请求监听地址管理
            myService.Add(px + "SqlLogPath/GetAll", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                var dto = httpC.Request.GetDtoByRequest("Query", new SearchLogPathsInputDto());
                return LogSqlPathConfigHelper.Searchs(dto);
            });
            myService.Add(px + "SqlLogPath/Del", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                var dto = httpC.Request.GetDtoByRequest("Query", new CUDLogPathsInputDto());
                return LogSqlPathConfigHelper.DeleteLogPaths(dto.PathJoins?.Split(','));
            });
            myService.Add(px + "SqlLogPath/AddOrSet", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                var dto = httpC.Request.GetDtoByRequest("Query", new CUDLogPathsInputDto());
                return LogSqlPathConfigHelper.SetAndAddLogPaths(dto.IsEnable, dto.PathJoins?.Split(','));
            });
            #endregion SqlLogPath 请求监听地址管理
            #region syslog 
            myService.Add(px + "SySLog/GetAll", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                var dto = httpC.Request.GetDtoByRequest("Query", new SysLogDto());
                return Db.SysLogHelper.GetInstance().Searchs(dto);
            });
            #endregion syslog
            #region deleteLog
            myService.Add(px + "Delete/GetLastDeleteTime", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                return WebLogHelper.GetLastDeleteTime();
            });
            myService.Add(px + "Delete/TryDelete", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                return WebLogHelper.GetLastDeleteTime(true);
            });
            #endregion deleteLog
            #region SearchLogInputDto
            myService.Add(px + "SearchLogInputDto/GetAll", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };

                var result = Extends.SearchExtend.GetSearchLogDtos(GetAndSetWLogId(httpC));
                if (result is Extends.SearchLogHistory)
                    return (result as Extends.SearchLogHistory).searchLogInputs;
                else return result;
            });
            #endregion SearchLogInputDto
            #region 邮件
            myService.Add(px + "Email/SendMail", (httpC) =>
            {
                if (!WebLogHelper.Config.ReadOpen) return new { msg = "未开启读取权限，请访问SetConfig api开启" };
                var dto = httpC.Request.GetDtoByRequest("Body", new Extends.EMailExtend.EMailInputDto());
                if (dto.PWD.IsNullEmpty() || !dto.PWD.Equals("@6947")) return "秘钥有误！";
                if (dto.Subject.IsNullEmpty()) dto.Subject = "意见反馈";
                if (dto.Body.IsNullEmpty()) return "消息格式有误！";
                var result = Extends.EMailExtend.SendEmail(dto.Subject, dto.Body);
                return result == null ? "发送成功~" : result;
            });
            #endregion 邮件
            myService.Add(px + "GetAllType", (httpC) => PageModels.GetControlTypes());
            foreach (var _service in myService)
            {
                app.Map(_service.Key, appBuilder =>
                {
                    appBuilder.Run(async httpC =>
                    {
                        httpC.Response.ContentType = "application/json";
                        var jr = JsonConvert.SerializeObject(_service.Value(httpC), CamelCase);
                        await httpC.Response.WriteAsync(jr, encoding: Encoding.UTF8);
                    });
                });
            }
        }

        /// <summary>
        /// 把文件资源响应到对应的网址上去
        /// </summary>
        /// <param name="app"></param>
        private static void WebLogResourcesResponse(IApplicationBuilder app)
        {
            //可以创建压缩包 然后解压到对应wwwroot路径
            //bool result = IISManager.CreateWebSite("tests", @"I:\code\海虹\Enterprise\EnterprisePlat.WebApi", "*:12345:");
            var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            var path = System.IO.Path.GetDirectoryName(currentAssembly.Location);//需要设置始终生成到目录
            Stack<string> files = new Stack<string>();
            Action<string> pushFilesByDirectoryPath = (_path) =>
            {
                foreach (var item in Directory.GetFileSystemEntries(_path))
                {
                    var ext = System.IO.Path.GetExtension(item).ToLower();
                    files.Push(item);
                }
            };
            var myDirPath = path + "\\Web";
            pushFilesByDirectoryPath(myDirPath);
            while (files.Count > 0)
            {
                var item = files.Pop();
                var ext = System.IO.Path.GetExtension(item).ToLower();
                if (ext == "")
                {
                    pushFilesByDirectoryPath(item);//深入子文件文件夹
                    continue;
                }
                var _url = item.Replace(path, "").Replace("\\", "/").Replace("/Web/", "/WebLog/");
                if (ext == ".html")
                    _url = _url.Replace(ext, "");
                string ct = null;
                ct = GetContentTypeByEXT(ext);
                app.Map(_url, appBuilder =>
                {
                    appBuilder.Run(async httpC =>
                    {
                        if (!WebLogHelper.Config.ReadOpen)
                        {
                            httpC.Response.ContentType = "text/plain; charset=utf-8";
                            await httpC.Response.WriteAsync("未开启读取权限，请访问SetConfig api开启", encoding: Encoding.UTF8);
                            return;
                        }
                        if (ct != null)
                            httpC.Response.ContentType = ct;
                        var item1 = item;
#if DEBUG
                        var src = System.Environment.CurrentDirectory;
                        item1 = src.Substring(0, src.LastIndexOf("\\")) + "\\WebLog" + item.Substring(item.LastIndexOf("\\Web\\"));
                        if (!File.Exists(item1)) item1 = item;
#endif
                        await httpC.Response.SendFileAsync(item1);
                    });
                });
            }
        }

        /// <summary>
        /// 获得后缀对应的扩展名
        /// </summary>
        /// <param name="ext">后缀</param>
        /// <returns></returns>
        private static string GetContentTypeByEXT(string ext)
        {
            string ct = "";
            switch (ext)//https://www.cnblogs.com/klb561/p/10090540.html
            {
                case ".html":
                    ct = "text/html; charset=utf-8";
                    break;

                case ".js":
                    ct = "application/javascript";
                    break;

                case ".css":
                    ct = "text/css";
                    break;

                case ".png":
                    ct = "image/png";
                    break;

                case ".ico":
                    ct = "image/x-icon";
                    break;

                case ".gif":
                    ct = "image/gif";
                    break;
            }

            return ct;
        }
    }
}